package com.shangfutai.android.keymonitoring

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.SurfaceTexture
import android.hardware.camera2.*
import android.media.MediaRecorder
import android.os.Bundle
import android.os.Handler
import android.os.HandlerThread
import android.util.Log
import android.util.Size
import android.view.Surface
import android.view.TextureView
import android.view.TextureView.SurfaceTextureListener
import androidx.annotation.NonNull
import androidx.appcompat.app.AppCompatActivity
import java.io.File
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.*

class VideoRecordingActivity : AppCompatActivity() {
    companion object {
        private var mActivity: VideoRecordingActivity? = null
        var isStartVideo = false
            private set

        fun stop() {
            if (isStartVideo) {
                mActivity?.let {
                    it.stopRecorder()
                    it.finish()
                }
            }

        }
    }

    private val TAG: String = VideoRecordingActivity::class.java.getSimpleName()

    lateinit var mTextureView: TextureView
    var mCameraManager: CameraManager? = null
    lateinit var mCameraDevice: CameraDevice
    var mCameraCaptureSession: CameraCaptureSession? = null
    lateinit var mCameraDeviceStateCallback: CameraDevice.StateCallback
    lateinit var mSessionStateCallback: CameraCaptureSession.StateCallback
    lateinit var mSessionCaptureCallback: CameraCaptureSession.CaptureCallback
    lateinit var mPreviewCaptureRequest: CaptureRequest.Builder
    lateinit var mMediaRecorder: MediaRecorder
    lateinit var mCurrentSelectCamera: String
    lateinit var mChildHandler: Handler
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        mActivity = this

        setContentView(R.layout.activity_video_recording)
        mTextureView = findViewById(R.id.textureview)

        initChildHandler()
        initTextureViewStateListener()
        initMediaRecorder()
        initCameraDeviceStateCallback()
        initSessionStateCallback()
        initSessionCaptureCallback()

    }


    private fun initTextureViewStateListener() {
        mTextureView.surfaceTextureListener = object : SurfaceTextureListener {
            override fun onSurfaceTextureAvailable(p0: SurfaceTexture, width: Int, height: Int) {
                initCameraManager()
                selectCamera()
                openCamera()
                //可以使用纹理
            }

            override fun onSurfaceTextureSizeChanged(p0: SurfaceTexture, width: Int, height: Int) {
                //纹理尺寸变化
            }

            override fun onSurfaceTextureDestroyed(p0: SurfaceTexture): Boolean {
                //纹理被销毁
                return false
            }

            override fun onSurfaceTextureUpdated(p0: SurfaceTexture) {
                //纹理更新
            }
        }
    }

    private fun initChildHandler() {
        val handlerThread = HandlerThread(TAG)
        handlerThread.start()
        mChildHandler = Handler(handlerThread.getLooper())
    }

    /**
     * 初始化MediaRecorder
     */
    private fun initMediaRecorder() {
        mMediaRecorder = MediaRecorder()
    }


    /**
     * 配置录制视频相关数据
     */
    @SuppressLint("SimpleDateFormat")
    private fun configMediaRecorder() {
        val simpleDateFormat = SimpleDateFormat("yyyyMMddHHmmssSS")
        val format = simpleDateFormat.format(Date(System.currentTimeMillis()))
        val file = File(externalCacheDir, "${format}.mp4")
        if (file.exists()) {
            file.delete()
        }
        mMediaRecorder.apply {
            setAudioSource(MediaRecorder.AudioSource.MIC) //设置音频来源
            setVideoSource(MediaRecorder.VideoSource.SURFACE) //设置视频来源
            setOutputFormat(MediaRecorder.OutputFormat.DEFAULT) //设置输出格式
            setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT) //设置音频编码格式，请注意这里使用默认，实际app项目需要考虑兼容问题，应该选择AAC
            setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT) //设置视频编码格式，请注意这里使用默认，实际app项目需要考虑兼容问题，应该选择H264
            setVideoEncodingBitRate(1 * 1920 * 1080) //设置比特率 一般是 1*分辨率 到 10*分辨率 之间波动。比特率越大视频越清晰但是视频文件也越大。
            setVideoFrameRate(30) //设置帧数 选择 30即可， 过大帧数也会让视频文件更大当然也会更流畅，但是没有多少实际提升。人眼极限也就30帧了。
            val size: Size = getMatchingSize2()
            setVideoSize(size.getWidth(), size.getHeight())
            setOrientationHint(0)
            val surface = Surface(mTextureView.surfaceTexture)
            setPreviewDisplay(surface)
            setOutputFile(file.getAbsolutePath())
            try {
                prepare()
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }

    }

    private fun config() {
        try {
            mCameraCaptureSession?.let {
                it.stopRepeating()
                it.close()
                mCameraCaptureSession = null
            }
        } catch (e: CameraAccessException) {
            e.printStackTrace()
        }
        configMediaRecorder()
        val cameraSize: Size = getMatchingSize2()
        val surfaceTexture = mTextureView.surfaceTexture
        surfaceTexture!!.setDefaultBufferSize(cameraSize.getWidth(), cameraSize.getHeight())
        val previewSurface = Surface(surfaceTexture)
        val recorderSurface = mMediaRecorder.surface //从获取录制视频需要的Surface
        try {
            mPreviewCaptureRequest =
                mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
            mPreviewCaptureRequest.set(
                CaptureRequest.CONTROL_AF_MODE,
                CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE
            )
            mPreviewCaptureRequest.addTarget(previewSurface)
            mPreviewCaptureRequest.addTarget(recorderSurface)
            //请注意这里设置了Arrays.asList(previewSurface,recorderSurface) 2个Surface，很好理解录制视频也需要有画面预览，第一个是预览的Surface，第二个是录制视频使用的Surface
            mCameraDevice.createCaptureSession(
                Arrays.asList(previewSurface, recorderSurface),
                mSessionStateCallback!!, mChildHandler
            )
        } catch (e: CameraAccessException) {
            e.printStackTrace()
        }
    }

    /**
     * 开始录制视频
     */
    private fun startRecorder() {
        isStartVideo = true
        mMediaRecorder.start()
    }

    /**
     * 暂停录制视频（暂停后视频文件会自动保存）
     */
    private fun stopRecorder() {
        isStartVideo = false
        mMediaRecorder.stop()
        mMediaRecorder.reset()
    }

    /**
     * 初始化Camera2的相机管理，CameraManager用于获取摄像头分辨率，摄像头方向，摄像头id与打开摄像头的工作
     */
    private fun initCameraManager() {
        mCameraManager = getSystemService(Context.CAMERA_SERVICE) as CameraManager
    }

    /**
     * 选择一颗我们需要使用的摄像头，主要是选择使用前摄还是后摄或者是外接摄像头
     */
    private fun selectCamera() {
        if (mCameraManager == null) {
            Log.e(TAG, "selectCamera: CameraManager is null")
        }
        try {
            val cameraIdList = mCameraManager!!.cameraIdList //获取当前设备的全部摄像头id集合
            if (cameraIdList.size == 0) {
                Log.e(TAG, "selectCamera: cameraIdList length is 0")
            }
            for (cameraId in cameraIdList) { //遍历所有摄像头
                val characteristics =
                    mCameraManager!!.getCameraCharacteristics(cameraId) //得到当前id的摄像头描述特征
                val facing = characteristics[CameraCharacteristics.LENS_FACING] //获取摄像头的方向特征信息
                if (facing === CameraCharacteristics.LENS_FACING_BACK) { //这里选择了后摄像头
                    mCurrentSelectCamera = cameraId
                }
            }
        } catch (e: CameraAccessException) {
            e.printStackTrace()
        }
    }

    private fun initCameraDeviceStateCallback() {
        mCameraDeviceStateCallback = object : CameraDevice.StateCallback() {
            override fun onOpened(@NonNull camera: CameraDevice) {
                //摄像头被打开
                try {
                    mCameraDevice = camera
                    val cameraSize: Size = getMatchingSize2() //计算获取需要的摄像头分辨率
                    val surfaceTexture = mTextureView.surfaceTexture //得到纹理
                    surfaceTexture!!.setDefaultBufferSize(
                        cameraSize.getWidth(),
                        cameraSize.getHeight()
                    )
                    val previewSurface = Surface(surfaceTexture)
                    mPreviewCaptureRequest =
                        mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
                    mPreviewCaptureRequest.set(
                        CaptureRequest.CONTROL_AF_MODE,
                        CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE
                    )
                    mPreviewCaptureRequest.addTarget(previewSurface)
                    mCameraDevice.createCaptureSession(
                        Arrays.asList(previewSurface),
                        mSessionStateCallback, mChildHandler
                    ) //创建数据捕获会话，用于摄像头画面预览，这里需要等待mSessionStateCallback回调
                } catch (e: CameraAccessException) {
                    e.printStackTrace()
                }
            }

            override fun onDisconnected(p0: CameraDevice) {
                //摄像头断开
            }

            override fun onError(p0: CameraDevice, p1: Int) {
                //异常
            }


        }


    }

    private fun initSessionStateCallback() {
        mSessionStateCallback = object : CameraCaptureSession.StateCallback() {
            override fun onConfigured(session: CameraCaptureSession) {
                mCameraCaptureSession = session
                try {
                    //执行重复获取数据请求，等于一直获取数据呈现预览画面，mSessionCaptureCallback会返回此次操作的信息回调
                    mCameraCaptureSession!!.setRepeatingRequest(
                        mPreviewCaptureRequest.build(),
                        mSessionCaptureCallback,
                        mChildHandler
                    )
                } catch (e: CameraAccessException) {
                    e.printStackTrace()
                }
            }

            override fun onConfigureFailed(session: CameraCaptureSession) {}
        }
    }

    private fun initSessionCaptureCallback() {
        mSessionCaptureCallback = object : CameraCaptureSession.CaptureCallback() {
            override fun onCaptureStarted(
                session: CameraCaptureSession,
                request: CaptureRequest,
                timestamp: Long,
                frameNumber: Long
            ) {
                super.onCaptureStarted(session, request, timestamp, frameNumber)
            }

            override fun onCaptureProgressed(
                session: CameraCaptureSession,
                request: CaptureRequest,
                partialResult: CaptureResult
            ) {
                super.onCaptureProgressed(session, request, partialResult)
            }

            override fun onCaptureCompleted(
                session: CameraCaptureSession,
                request: CaptureRequest,
                result: TotalCaptureResult
            ) {
                super.onCaptureCompleted(session, request, result)
            }

            override fun onCaptureFailed(
                session: CameraCaptureSession,
                request: CaptureRequest,
                failure: CaptureFailure
            ) {
                super.onCaptureFailed(session, request, failure)
            }
        }
    }

    /**
     * 打开摄像头，这里打开摄像头后，我们需要等待mCameraDeviceStateCallback的回调
     */
    @SuppressLint("MissingPermission")
    private fun openCamera() {
        try {
            mCameraManager!!.openCamera(
                mCurrentSelectCamera,
                mCameraDeviceStateCallback, mChildHandler
            )
        } catch (e: CameraAccessException) {
            e.printStackTrace()
            Log.e("TAG", "==" + e.toString())
        }
        config()
        startRecorder()
    }


    /**
     * 计算需要的使用的摄像头分辨率
     * @return
     */
    private fun getMatchingSize2(): Size {
        return Size(640, 480)
    }

    override fun onPause() {
        super.onPause()
        stopRecorder()
    }

}